package controllers

import (
	"context"
	"errors"
	"github.com/gin-gonic/gin"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	"go.didapinche.com/foundation/plat-echo/app/ops/models/request"
	"go.didapinche.com/foundation/plat-echo/app/ops/services"
	"go.didapinche.com/foundation/plat-echo/pkg/constants"
	dtime "go.didapinche.com/time"
	"go.uber.org/zap"
	"net/http"
	"strconv"
	"time"
)

type AlertHistoryController struct {
	service services.AlertHistoryService
	logger  *zap.Logger
}

func NewAlertHistoryController(service services.AlertHistoryService, logger *zap.Logger) *AlertHistoryController {
	return &AlertHistoryController{
		service: service,
		logger:  logger.With(zap.String("type", "controller.alert_history")),
	}
}

func (h *AlertHistoryController) Claim(c *gin.Context) {
	param := new(struct {
		IDs []*request.Alert `json:"alerts"`
	})
	err := c.Bind(param)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	Owner := new(models.ApplicationOwner)
	userID := c.GetString("UserID")
	userName := c.GetString("UserName")
	if err := h.service.Claim(c.Request.Context(), param.IDs, userID, userName); err != nil {
		if errors.Is(err, context.Canceled) {
			h.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		h.logger.Error("call AlertRecordController.FindAlertRecord() error", zap.Error(err))
		c.String(http.StatusInternalServerError, "call AlertRecordController.FindAlertRecord() error:%v", err)
		return
	}
	Owner.UserID = userID
	Owner.UserName = userName
	c.JSON(http.StatusOK, Owner)
}

func (h *AlertHistoryController) Find(c *gin.Context) {
	param := &request.AlertHistoryReq{}
	err := c.BindQuery(param)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	if param.PageNum == 0 {
		param.PageNum = 1
	}
	if param.PageSize == 0 {
		param.PageSize = 20
	}

	if len(param.Start) > 0 {
		start, err := time.ParseInLocation("2006-01-02 15:04:05", param.Start, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.StartTime = dtime.Time{start}
	}
	if len(param.End) > 0 {
		end, err := time.ParseInLocation("2006-01-02 15:04:05", param.End, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.EndTime = dtime.Time{end}
	}
	reps, count, err := h.service.Find(c.Request.Context(), param)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			h.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		h.logger.Error("call AlertRecordController.FindAlertRecord() error", zap.Error(err))
		c.String(http.StatusInternalServerError, "call AlertRecordController.FindAlertRecord() error:%v", err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"data":        reps,
		"total_count": count,
	})
}

func (h *AlertHistoryController) FindStatHistory(c *gin.Context) {
	params := new(struct {
		AppID      uint64 `form:"app_id"`
		MetricType string `form:"metric_type"`
		Start      string `form:"start" json:"start,omitempty"`
		End        string `form:"end" json:"end,omitempty"`
		PageNum    int    `form:"page_num"`
		PageSize   int    `form:"page_size"`
	})
	if err := c.BindQuery(params); err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind params error:%v", err)
		return
	}
	start, err := time.ParseInLocation("2006-01-02 15:04:05", params.Start, time.Local)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "start time convert error:%v", err)
		return
	}
	end, err := time.ParseInLocation("2006-01-02 15:04:05", params.End, time.Local)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "end time convert error:%v", err)
		return
	}

	histories, count, err := h.service.FindStatHistory(c.Request.Context(), params.AppID, params.MetricType, dtime.Time{start}, dtime.Time{end}, params.PageNum, params.PageSize)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			h.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		h.logger.Error("call AlertStatService.FindStatHistory() error", zap.Error(err))
		c.String(http.StatusInternalServerError, "call AlertStatService.FindStatHistory() error:%v", err)
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"data":        histories,
		"total_count": count,
	})
}

func (h *AlertHistoryController) FindAlertCountByAppId(c *gin.Context) {
	param := new(struct {
		AppID uint64 `json:"app_id"`
		Start string `form:"start"`
		End   string `form:"end"`
	})
	err := c.Bind(param)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	start, err := time.ParseInLocation("2006-01-02 15:04:05", param.Start, time.Local)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	end, err := time.ParseInLocation("2006-01-02 15:04:05", param.End, time.Local)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "convert id to integer error")
		return
	}
	param.AppID = id

	countStat, err := h.service.FindAlertCountByAppId((c.Request.Context()), param.AppID, dtime.Time{start}, dtime.Time{end})
	if err != nil {
		if errors.Is(err, context.Canceled) {
			h.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		h.logger.Error("call AlertRecordController.FindAlertCountByAppId() error", zap.Error(err))
		c.String(http.StatusInternalServerError, "call AlertRecordController.FindAlertCountByAppId() error:%v", err)
		return
	}
	c.JSON(http.StatusOK, countStat)
}

func (h *AlertHistoryController) FindAlertRecord(c *gin.Context) {
	param := &request.AlertRecordReq{}
	err := c.BindQuery(param)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	if param.PageNum == 0 {
		param.PageNum = 1
	}
	if param.PageSize == 0 {
		param.PageSize = 20
	}

	if param.GraphID == 0 {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	if len(param.Start) > 0 {
		start, err := time.ParseInLocation("2006-01-02 15:04:05", param.Start, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.StartTime = dtime.Time{start}
	}
	if len(param.End) > 0 {
		end, err := time.ParseInLocation("2006-01-02 15:04:05", param.End, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.EndTime = dtime.Time{end}
	}
	reps, count, err := h.service.FindAlertRecord(c.Request.Context(), param)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			h.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		h.logger.Error("call AlertRecordController.FindAlertRecord() error", zap.Error(err))
		c.String(http.StatusInternalServerError, "call AlertRecordController.FindAlertRecord() error:%v", err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"data":        reps,
		"total_count": count,
	})
}

func (h *AlertHistoryController) FindAlertRecordByAppId(c *gin.Context) {
	param := &request.AlertRecordReq{}
	err := c.BindQuery(param)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "convert id to integer error")
		return
	}
	param.AppID = id
	if len(param.Start) > 0 {
		start, err := time.ParseInLocation("2006-01-02 15:04:05", param.Start, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.StartTime = dtime.Time{start}
	}
	if len(param.End) > 0 {
		h.logger.Error("bind param error", zap.Error(err))
		end, err := time.ParseInLocation("2006-01-02 15:04:05", param.End, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.EndTime = dtime.Time{end}
	}
	reps, count, alertCount, err := h.service.FindAlertRecordByAppID(c.Request.Context(), param)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			h.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		h.logger.Error("call AlertRecordController.FindAlertRecord() error", zap.Error(err))
		c.String(http.StatusInternalServerError, "call AlertRecordController.FindAlertRecord() error:%v", err)
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"data":        reps,
		"total_count": count * 2,
		"alert_count": alertCount + count,
	})
}

func (h *AlertHistoryController) FindAlertHistoryByApiId(c *gin.Context) {
	param := &request.AlertRecordReq{}
	err := c.BindQuery(param)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	id, err := strconv.ParseUint(c.Query("id"), 10, 64)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "convert id to integer error")
		return
	}
	param.ApiID = id
	if len(param.Start) > 0 {
		start, err := time.ParseInLocation("2006-01-02 15:04:05", param.Start, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.StartTime = dtime.Time{start}
	}
	if len(param.End) > 0 {
		end, err := time.ParseInLocation("2006-01-02 15:04:05", param.End, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.EndTime = dtime.Time{end}
	}
	reps, count, err := h.service.FindAlertHistoryByApiID(c.Request.Context(), param)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			h.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		h.logger.Error("call AlertRecordController.FindAlertRecord() error", zap.Error(err))
		c.String(http.StatusInternalServerError, "call AlertRecordController.FindAlertRecord() error:%v", err)
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"data":        reps,
		"total_count": count,
	})
}

func (h *AlertHistoryController) FindAlertRecordByDashboardID(c *gin.Context) {
	param := &request.AlertRecordReq{}
	err := c.BindQuery(param)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "convert id to integer error")
		return
	}
	param.DashboardID = id
	if len(param.Start) > 0 {
		start, err := time.ParseInLocation("2006-01-02 15:04:05", param.Start, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.StartTime = dtime.Time{start}
	}
	if len(param.End) > 0 {
		end, err := time.ParseInLocation("2006-01-02 15:04:05", param.End, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.EndTime = dtime.Time{end}
	}
	reps, count, alertCount, err := h.service.FindAlertRecordByAppID(c.Request.Context(), param)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			h.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		h.logger.Error("call AlertRecordController.FindAlertRecord() error", zap.Error(err))
		c.String(http.StatusInternalServerError, "call AlertRecordController.FindAlertRecord() error:%v", err)
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"data":        reps,
		"total_count": count * 2,
		"alert_count": alertCount + count,
	})
}

func (h *AlertHistoryController) FindAlertRecordByApiID(c *gin.Context) {
	param := &request.AlertRecordReq{}
	err := c.BindQuery(param)
	if err != nil {
		h.logger.Error("bind param error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind param error:%v", err)
		return
	}
	if len(param.Start) > 0 {
		start, err := time.ParseInLocation("2006-01-02 15:04:05", param.Start, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.StartTime = dtime.Time{start}
	}
	if len(param.End) > 0 {
		end, err := time.ParseInLocation("2006-01-02 15:04:05", param.End, time.Local)
		if err != nil {
			h.logger.Error("bind param error", zap.Error(err))
			c.String(http.StatusBadRequest, "bind param error:%v", err)
			return
		}
		param.EndTime = dtime.Time{end}
	}
	reps, count, alertCount, err := h.service.FindAlertRecordByApiID(c.Request.Context(), param)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			h.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		h.logger.Error("call AlertRecordController.FindAlertRecord() error", zap.Error(err))
		c.String(http.StatusInternalServerError, "call AlertRecordController.FindAlertRecord() error:%v", err)
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"data":        reps,
		"total_count": count * 2,
		"alert_count": alertCount + count,
	})
}

// 清理数据
func (h *AlertHistoryController) DeleteByRepeat(c *gin.Context) {

	err := h.service.DeleteByRepeat(c.Request.Context())
	if err != nil {
		h.logger.Error("call AlertRecordController.FindAlertRecord() error", zap.Error(err))
		c.String(http.StatusInternalServerError, "call AlertRecordController.FindAlertRecord() error:%v", err)
		return
	}
	c.JSON(http.StatusOK, "ok")
}
